/*
 * radiofunc.cpp - V4L2 radio device interface
 *
 * Copyright (C) 2010-2011 Serge Begger
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "radiofunc.h"
#include <linux/videodev2.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>

radiofunc::radiofunc()
{
    freq_fact = 16000;
    tunerOk = true;
}

void radiofunc::closeTuner()
{
    if (fd >= 0)
        close(fd);
    fd = -1;
}

bool radiofunc::initTuner(QString devName)
{
        struct v4l2_capability caps;
        struct v4l2_tuner tuner;

        fd = open(devName.toLatin1(), O_RDONLY);
        if (fd < 0) {
                printf("Tuner is not active");
                tunerOk = false;
                return false;
            }

        /* does this device provide a tuner? */
        memset(&caps, 0, sizeof(caps));
        if (ioctl(fd, VIDIOC_QUERYCAP, &caps) < 0) {
                perror("VIDIOC_QUERYCAP");
                tunerOk = false;
                return false;
        }
        if ((caps.capabilities & V4L2_CAP_TUNER) == 0) {
                printf("Not a radio tuner\n");
                tunerOk = false;
                return false;
        }

        /* check the tuner */
        memset(&tuner, 0, sizeof(tuner));
        tuner.index = 0;
        if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0) {
                perror("VIDIOC_G_TUNER");
                tunerOk = false;
                return false;
        }
        if (tuner.type != V4L2_TUNER_RADIO) {
                printf("Not a radio tuner\n");
                tunerOk = false;
                return false;
        }
        /* Does this tuner expect data in 62.5Hz or 62.5kHz multiples? */
        if ((tuner.capability & V4L2_TUNER_CAP_LOW) != 0)
                freq_fact = 16000;
        else
                freq_fact = 16;

        return true;
 };

void radiofunc::setFreq(double frequency)
{
    if (tunerOk) {
        struct v4l2_frequency freq;
        freq.tuner = 0;
        freq.type = V4L2_TUNER_RADIO;
        freq.frequency = frequency * freq_fact;
        if (ioctl(fd, VIDIOC_S_FREQUENCY, &freq) < 0)
            perror("VIDIOC_S_FREQUENCY");
    }
}

int radiofunc::getSignal()
{
    if (tunerOk) {
        struct v4l2_tuner tuner;
        if (fd < 0)
            return -1;
        memset(&tuner, 0, sizeof(tuner));
        tuner.index = 0;
        if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0) {
            perror("VIDIOC_G_TUNER");
            return -1;
        }
        return (int)tuner.signal / 65535 * 100;
    }
    return -1;
}

int radiofunc::getStereo()
{
    if (tunerOk) {
        struct v4l2_tuner tuner;

        if (fd<0)
            return -1;

        memset(&tuner, 0, sizeof(tuner));
        tuner.index = 0;
        if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0) {
            perror("VIDIOC_G_TUNER");
            return -1;
        }
        return tuner.audmode == V4L2_TUNER_MODE_STEREO;
    } else return -1;
}

void radiofunc::radioMute(bool mute)
{
    if (tunerOk) {
        struct v4l2_control control;

        if (fd<0)
            return;

        memset(&control, 0, sizeof(control));
        control.id = V4L2_CID_AUDIO_MUTE;
        control.value = mute;
        if (ioctl(fd, VIDIOC_S_CTRL, &control) < 0)
            perror("VIDIOC_S_CTRL");
    }
}

